package com.bblocks.dbmonitor.handler.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.bblocks.dbmonitor.annotation.MonitorTable;
import com.bblocks.dbmonitor.config.MonitorTableServiceInfo;
import com.bblocks.dbmonitor.handler.RecordChangedHandler;
import com.google.common.collect.Lists;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.core.Ordered;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Array;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * <p>Project: bblocks-pro - RecordChangedFreshCacheHandler</p>
 * <p>描述：缓存清理（默认删除id缓存）</p>
 *
 * @Author Zhao [125043150@qq.com]
 * @Date 2024/1/15 15:49
 * @Version 1.0
 * @since 8
 */
@RequiredArgsConstructor
@Slf4j
public class RecordChangedEvictCacheHandler extends RecordChangedHandler {

    private final CacheManager cacheManager;

    private SpelExpressionParser spelParser = new SpelExpressionParser();

    /**
     * 缓存新增好像也没啥 需要处理（可以清理下缓存？根据ID）
     * @param map
     * @param monitorTableServiceInfo
     */
    public  void saved(Map<String, String> map,@NonNull MonitorTableServiceInfo monitorTableServiceInfo) {
        if(log.isDebugEnabled())
            log.debug("增加 {}", map);

        //
        evictRecordCache(monitorTableServiceInfo,map);
    }

    /**
     *
     * @param before
     * @param after
     * @param monitorTableServiceInfo
     */
    public void updated(Map<String, String> before, Map<String, String> after,@NonNull MonitorTableServiceInfo monitorTableServiceInfo){
        if(log.isDebugEnabled()) {
            log.debug("修改 before {}", before);
            log.debug("修改 after {}", after);
        }

        evictRecordCache(monitorTableServiceInfo,after);
    }

    /**
     *
     * @param map
     * @param monitorTableServiceInfo
     */
    public  void deleted(Map<String, String> map,@NonNull MonitorTableServiceInfo monitorTableServiceInfo) {
        log.info("删除 {}", map);

        evictRecordCache(monitorTableServiceInfo,map);
    }

    public int getOrder() {
        return 0;
    }


    private int evictRecordCache(@NonNull MonitorTableServiceInfo monitorTableServiceInfo,@NonNull Map<String, String> record){
        MonitorTable monitorTable = monitorTableServiceInfo.getMonitorTable();

        String idKey = monitorTable.id();
        if(StrUtil.isEmpty(idKey))
            return 0;

        String tableName = monitorTable.value();
        String id = record.get(StrUtil.toUnderlineCase(idKey));
        if(StrUtil.isEmpty(id)){
            log.warn("表:{} 更新后，未找到id：{} 值,无法清理缓存！",tableName,idKey);
            return 0;
        }

        String[] cacheNames = monitorTableServiceInfo.getCacheNames();
        if(cacheNames == null || cacheNames.length == 0){
            log.warn("表:{} 更新后，cacheNames未配置（@CacheConfig(cacheNames = \"xxx\")），无法清理缓存！",tableName);
            return 0;
        }


        String[] cacheKeySpels = monitorTable.cacheKeySpels();
        List<String> cacheKeys = Lists.newArrayListWithCapacity(ArrayUtil.isEmpty(cacheKeySpels)?1:cacheKeySpels.length);
        if (ArrayUtil.isEmpty(cacheKeySpels)){
            cacheKeys.add(id);
        }else{
            //将方法的参数名和参数值一一对应的放入上下文中
            EvaluationContext ctx = new StandardEvaluationContext();
            record.forEach((k,v)->{
                ctx.setVariable(StrUtil.toCamelCase(k), v);
            });

            Stream.of(cacheKeySpels).forEach(s->{
                //解析SpEL表达式获取结果
                String value = spelParser.parseExpression(s).getValue(ctx).toString();
                cacheKeys.add(value);
            });
        }

        Stream.of(cacheNames)
                .forEach(cn->{
            try {
                evictIdCache(cn, cacheKeys);
            }catch (Exception e){log.error("evictIdCache exp:",e);}
        });

        return 1;
    }

    private void evictIdCache(@NonNull String cacheName,@NonNull List<String> cacheKeys){
        Optional.ofNullable(cacheManager.getCache(cacheName))
                .ifPresent(cm->{
                    cacheKeys.forEach(cacheKey->{
                        log.debug("开始删除cacheName：{} ，key:{}",cacheName,cacheKey);
                        cm .evict(cacheKey);
                    });
                });
    }
}
